From: Mario Sanchez Prada Date: Mon, 5 Jun 2017 17:36:41 +0000 (+0100) Subject: st-entry: Add support for a "hint actor" X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~1013^2^2~301 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=6ed7034a6bb5afa1acb003183eb5bdd1ca1542f6;p=gnome-shell.git st-entry: Add support for a "hint actor" This allows a full ClutterActor to be used as hint in the entry, instead of a simple string. The string case has been now re-implemented on top of the hint actor. https://bugzilla.gnome.org/show_bug.cgi?id=783484 --- diff --git a/src/st/st-entry.c b/src/st/st-entry.c index c92991e3f..fc9ffbffd 100644 --- a/src/st/st-entry.c +++ b/src/st/st-entry.c @@ -34,7 +34,7 @@ * focus: the widget has focus * * - * indeterminate: the widget is showing the hint text + * indeterminate: the widget is showing the hint text or actor * * */ @@ -56,6 +56,7 @@ #include "st-im-text.h" #include "st-icon.h" +#include "st-label.h" #include "st-widget.h" #include "st-texture-cache.h" #include "st-clipboard.h" @@ -75,6 +76,7 @@ enum PROP_PRIMARY_ICON, PROP_SECONDARY_ICON, PROP_HINT_TEXT, + PROP_HINT_ACTOR, PROP_TEXT, PROP_INPUT_PURPOSE, PROP_INPUT_HINTS, @@ -96,14 +98,14 @@ typedef struct _StEntryPrivate StEntryPrivate; struct _StEntryPrivate { ClutterActor *entry; - gchar *hint; ClutterActor *primary_icon; ClutterActor *secondary_icon; + ClutterActor *hint_actor; + gfloat spacing; - gboolean hint_visible; gboolean capslock_warning_shown; gboolean has_ibeam; @@ -140,6 +142,10 @@ st_entry_set_property (GObject *gobject, st_entry_set_hint_text (entry, g_value_get_string (value)); break; + case PROP_HINT_ACTOR: + st_entry_set_hint_actor (entry, g_value_get_object (value)); + break; + case PROP_TEXT: st_entry_set_text (entry, g_value_get_string (value)); break; @@ -181,7 +187,11 @@ st_entry_get_property (GObject *gobject, break; case PROP_HINT_TEXT: - g_value_set_string (value, priv->hint); + g_value_set_string (value, st_entry_get_hint_text (ST_ENTRY (gobject))); + break; + + case PROP_HINT_ACTOR: + g_value_set_object (value, priv->hint_actor); break; case PROP_TEXT: @@ -265,14 +275,21 @@ st_entry_dispose (GObject *object) } static void -st_entry_finalize (GObject *object) +st_entry_update_hint_visibility (StEntry *self) { - StEntryPrivate *priv = ST_ENTRY_PRIV (object); + StEntryPrivate *priv = ST_ENTRY_PRIV (self); + gboolean hint_visible = + priv->hint_actor != NULL && + strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "") == 0 && + !HAS_FOCUS (priv->entry); - g_free (priv->hint); - priv->hint = NULL; + if (priv->hint_actor) + g_object_set (priv->hint_actor, "visible", hint_visible, NULL); - G_OBJECT_CLASS (st_entry_parent_class)->finalize (object); + if (hint_visible) + st_widget_add_style_pseudo_class (ST_WIDGET (self), "indeterminate"); + else + st_widget_remove_style_pseudo_class (ST_WIDGET (self), "indeterminate"); } static void @@ -352,7 +369,7 @@ st_entry_get_preferred_width (ClutterActor *actor, { StEntryPrivate *priv = ST_ENTRY_PRIV (actor); StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); - gfloat icon_w; + gfloat hint_w, icon_w; st_theme_node_adjust_for_height (theme_node, &for_height); @@ -360,6 +377,17 @@ st_entry_get_preferred_width (ClutterActor *actor, min_width_p, natural_width_p); + if (priv->hint_actor) + { + clutter_actor_get_preferred_width (priv->hint_actor, -1, NULL, &hint_w); + + if (min_width_p && hint_w > *min_width_p) + *min_width_p = hint_w; + + if (natural_width_p && hint_w > *natural_width_p) + *natural_width_p = hint_w; + } + if (priv->primary_icon) { clutter_actor_get_preferred_width (priv->primary_icon, -1, NULL, &icon_w); @@ -394,7 +422,7 @@ st_entry_get_preferred_height (ClutterActor *actor, { StEntryPrivate *priv = ST_ENTRY_PRIV (actor); StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); - gfloat icon_h; + gfloat hint_h, icon_h; st_theme_node_adjust_for_width (theme_node, &for_width); @@ -402,6 +430,17 @@ st_entry_get_preferred_height (ClutterActor *actor, min_height_p, natural_height_p); + if (priv->hint_actor) + { + clutter_actor_get_preferred_height (priv->hint_actor, -1, NULL, &hint_h); + + if (min_height_p && hint_h > *min_height_p) + *min_height_p = hint_h; + + if (natural_height_p && hint_h > *natural_height_p) + *natural_height_p = hint_h; + } + if (priv->primary_icon) { clutter_actor_get_preferred_height (priv->primary_icon, @@ -436,12 +475,16 @@ st_entry_allocate (ClutterActor *actor, { StEntryPrivate *priv = ST_ENTRY_PRIV (actor); StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); - ClutterActorBox content_box, child_box, icon_box; + ClutterActorBox content_box, child_box, icon_box, hint_box; gfloat icon_w, icon_h; + gfloat hint_w, hint_h; gfloat entry_h, min_h, pref_h, avail_h; ClutterActor *left_icon, *right_icon; + gboolean is_rtl; + + is_rtl = clutter_actor_get_text_direction (actor) == CLUTTER_TEXT_DIRECTION_RTL; - if (clutter_actor_get_text_direction (actor) == CLUTTER_TEXT_DIRECTION_RTL) + if (is_rtl) { right_icon = priv->primary_icon; left_icon = priv->secondary_icon; @@ -495,6 +538,25 @@ st_entry_allocate (ClutterActor *actor, child_box.x2 = MAX (child_box.x1, child_box.x2 - icon_w - priv->spacing); } + if (priv->hint_actor) + { + /* now allocate the hint actor */ + hint_box = child_box; + + clutter_actor_get_preferred_width (priv->hint_actor, -1, NULL, &hint_w); + clutter_actor_get_preferred_height (priv->hint_actor, -1, NULL, &hint_h); + + if (is_rtl) + hint_box.x1 = hint_box.x2 - hint_w; + else + hint_box.x2 = hint_box.x1 + hint_w; + + hint_box.y1 = ceil (content_box.y1 + avail_h / 2 - hint_h / 2); + hint_box.y2 = hint_box.y1 + hint_h; + + clutter_actor_allocate (priv->hint_actor, &hint_box, flags); + } + clutter_actor_get_preferred_height (priv->entry, child_box.x2 - child_box.x1, &min_h, &pref_h); @@ -511,23 +573,15 @@ clutter_text_focus_in_cb (ClutterText *text, ClutterActor *actor) { StEntry *entry = ST_ENTRY (actor); - StEntryPrivate *priv = ST_ENTRY_PRIV (entry); GdkKeymap *keymap; - /* remove the hint if visible */ - if (priv->hint && priv->hint_visible) - { - priv->hint_visible = FALSE; - - clutter_text_set_text (text, ""); - } + st_entry_update_hint_visibility (entry); keymap = gdk_keymap_get_for_display (gdk_display_get_default ()); keymap_state_changed (keymap, entry); g_signal_connect (keymap, "state-changed", G_CALLBACK (keymap_state_changed), entry); - st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "indeterminate"); st_widget_add_style_pseudo_class (ST_WIDGET (actor), "focus"); clutter_text_set_cursor_visible (text, TRUE); } @@ -537,19 +591,12 @@ clutter_text_focus_out_cb (ClutterText *text, ClutterActor *actor) { StEntry *entry = ST_ENTRY (actor); - StEntryPrivate *priv = ST_ENTRY_PRIV (entry); GdkKeymap *keymap; st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "focus"); - /* add a hint if the entry is empty */ - if (priv->hint && !strcmp (clutter_text_get_text (text), "")) - { - priv->hint_visible = TRUE; + st_entry_update_hint_visibility (entry); - clutter_text_set_text (text, priv->hint); - st_widget_add_style_pseudo_class (ST_WIDGET (actor), "indeterminate"); - } clutter_text_set_cursor_visible (text, FALSE); remove_capslock_feedback (entry); @@ -870,7 +917,6 @@ st_entry_class_init (StEntryClass *klass) gobject_class->set_property = st_entry_set_property; gobject_class->get_property = st_entry_get_property; - gobject_class->finalize = st_entry_finalize; gobject_class->dispose = st_entry_dispose; actor_class->get_preferred_width = st_entry_get_preferred_width; @@ -917,6 +963,14 @@ st_entry_class_init (StEntryClass *klass) NULL, G_PARAM_READWRITE); g_object_class_install_property (gobject_class, PROP_HINT_TEXT, pspec); + pspec = g_param_spec_object ("hint-actor", + "Hint Actor", + "An actor to display when the entry is not focused " + "and the text property is empty", + CLUTTER_TYPE_ACTOR, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, PROP_HINT_ACTOR, pspec); + pspec = g_param_spec_string ("text", "Text", "Text of the entry", @@ -1052,7 +1106,7 @@ st_entry_get_text (StEntry *entry) g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); priv = st_entry_get_instance_private (entry); - if (priv->hint_visible) + if (clutter_actor_is_visible (priv->hint_actor)) return ""; else return clutter_text_get_text (CLUTTER_TEXT (priv->entry)); @@ -1075,24 +1129,10 @@ st_entry_set_text (StEntry *entry, priv = st_entry_get_instance_private (entry); - /* set a hint if we are blanking the entry */ - if (priv->hint - && text && !strcmp ("", text) - && !HAS_FOCUS (priv->entry)) - { - text = priv->hint; - priv->hint_visible = TRUE; - st_widget_add_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); - } - else - { - st_widget_remove_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); - - priv->hint_visible = FALSE; - } - clutter_text_set_text (CLUTTER_TEXT (priv->entry), text); + st_entry_update_hint_visibility (entry); + g_object_notify (G_OBJECT (entry), "text"); } @@ -1126,24 +1166,12 @@ void st_entry_set_hint_text (StEntry *entry, const gchar *text) { - StEntryPrivate *priv; + StWidget *label; g_return_if_fail (ST_IS_ENTRY (entry)); - priv = st_entry_get_instance_private (entry); - - g_free (priv->hint); - - priv->hint = g_strdup (text); - - if (!strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "") - && !HAS_FOCUS (priv->entry)) - { - priv->hint_visible = TRUE; - - clutter_text_set_text (CLUTTER_TEXT (priv->entry), priv->hint); - st_widget_add_style_pseudo_class (ST_WIDGET (entry), "indeterminate"); - } + label = st_label_new (text); + st_entry_set_hint_actor (ST_ENTRY (entry), CLUTTER_ACTOR (label)); } /** @@ -1158,9 +1186,16 @@ st_entry_set_hint_text (StEntry *entry, const gchar * st_entry_get_hint_text (StEntry *entry) { + StEntryPrivate *priv; + g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); - return ((StEntryPrivate *)ST_ENTRY_PRIV (entry))->hint; + priv = ST_ENTRY_PRIV (entry); + + if (priv->hint_actor != NULL && ST_IS_LABEL (priv->hint_actor)) + return st_label_get_text (ST_LABEL (priv->hint_actor)); + + return NULL; } /** @@ -1370,6 +1405,57 @@ st_entry_get_secondary_icon (StEntry *entry) return priv->secondary_icon; } +/** + * st_entry_set_hint_actor: + * @entry: a #StEntry + * @hint_actor: (allow-none): a #ClutterActor + * + * Set the hint actor of the entry to @hint_actor + */ +void +st_entry_set_hint_actor (StEntry *entry, + ClutterActor *hint_actor) +{ + StEntryPrivate *priv; + + g_return_if_fail (ST_IS_ENTRY (entry)); + + priv = ST_ENTRY_PRIV (entry); + + if (priv->hint_actor != NULL) + { + clutter_actor_remove_child (CLUTTER_ACTOR (entry), priv->hint_actor); + priv->hint_actor = NULL; + } + + if (hint_actor != NULL) + { + priv->hint_actor = hint_actor; + clutter_actor_add_child (CLUTTER_ACTOR (entry), priv->hint_actor); + } + + st_entry_update_hint_visibility (entry); + + clutter_actor_queue_relayout (CLUTTER_ACTOR (entry)); +} + +/** + * st_entry_get_hint_actor: + * @entry: a #StEntry + * + * Returns: (transfer none): a #ClutterActor + */ +ClutterActor * +st_entry_get_hint_actor (StEntry *entry) +{ + StEntryPrivate *priv; + + g_return_val_if_fail (ST_IS_ENTRY (entry), NULL); + + priv = ST_ENTRY_PRIV (entry); + return priv->hint_actor; +} + /******************************************************************************/ /*************************** ACCESSIBILITY SUPPORT ****************************/ /******************************************************************************/ diff --git a/src/st/st-entry.h b/src/st/st-entry.h index 1fbc5561c..43ae0fa4c 100644 --- a/src/st/st-entry.h +++ b/src/st/st-entry.h @@ -65,6 +65,10 @@ void st_entry_set_secondary_icon (StEntry *entry, ClutterActor *icon); ClutterActor * st_entry_get_secondary_icon (StEntry *entry); +void st_entry_set_hint_actor (StEntry *entry, + ClutterActor *hint_actor); +ClutterActor * st_entry_get_hint_actor (StEntry *entry); + typedef void (*StEntryCursorFunc) (StEntry *entry, gboolean use_ibeam, gpointer data); void st_entry_set_cursor_func (StEntryCursorFunc func, gpointer user_data);